home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_asm / prtspl2 / mspool.asm next >
Encoding:
Assembly Source File  |  1986-11-22  |  23.5 KB  |  517 lines

  1. Comment *
  2.                       Multi Spooler Ver. 2
  3.                          for the IBM PC
  4.                          by Rich Winkel
  5.                           Columbia, Mo.
  6.  
  7.                    For free distribution only
  8.  
  9.                         Mspool2 Features
  10.  
  11.      Allows spooling up to 4 printers simultaneously.
  12.      Supports both parallel and serial printers in any
  13.           combination.
  14.      Has a user selectable buffer size up to 63K bytes.
  15.      Sensitive to competing demands for CPU time.  Won't
  16.           slow down foreground jobs.
  17.      Allows cancellation of an on-going print operation.
  18.      Can be 'disabled' for use with programs which are
  19.           incompatible with it's operation.
  20.  
  21.  
  22. Usage:
  23.  
  24. To install the spooler, at the DOS prompt type:
  25.  
  26.           MSPOOL a b c
  27. where:
  28.  
  29. a (= 1 - 4) represents the four possible printers on the PC.
  30.             (1, 2 & 3 correspond to LPT1, LPT2 & LPT3)
  31.  
  32. b (= 1 - 9) represents the number of 7K chunks of memory to set
  33.             aside for the spooler buffer.
  34.  
  35. c (= 1 - 4) is an optional parameter used when you wish the
  36.             output to be directed to a serial port.
  37.             (1 and 2 correspond to COM1 and COM2)
  38.  
  39.      Once the spooler is installed, the user need not worry about
  40. it further; it will begin intercepting all print operations and
  41. buffering them.  However, the operation of the spooler can be
  42. modified after it has been installed, if the need arises.  After
  43. the spooler has been installed, if you type:
  44.  
  45.           MSPOOL a
  46.  
  47.      where 'a' is the same 'a' you used to install it, you are
  48. presented with three options: Purge, Disable or Enable.  These
  49. are as follows:
  50.  
  51. Purge:    Drops any characters remaining in the spooler buffer.
  52.           This has the effect of canceling any printing operation
  53.           currently taking place.
  54.  
  55. Disable:  A few programs for the PC operate in a way which
  56.           interferes with MSPOOL's ability to send characters to
  57.           the printer.  The result is that MSPOOL captures the
  58.           characters, but doesn't actually begin printing them
  59.           until it's buffer is full or you exit your program.
  60.           'Disabling' the spooler (prior to running your program)
  61.           keeps the number of characters in it's buffer from
  62.           growing.  That is, every time the spooler intercepts a
  63.           character, it prints a character.  If it's buffer is
  64.           empty, it's as if it wasn't there at all.  It simply
  65.           prints the character it gets when it gets it.  If there
  66.           are characters in the buffer at the time the offending
  67.           program is invoked, then when it gets a character to
  68.           print, it fetches the next character in line and prints
  69.           it, and puts the new character at the end of the queue.
  70.  
  71. Enable:   Re-enables spooling.
  72.  
  73.      Hitting any key other than P, D or E has no effect.
  74.  
  75. Notes:
  76.  
  77.      To spool to a serial printer, first initialize the COM port
  78. with the MODE command: MODE COMc:baud,parity,databits,stopbits
  79. etc.  DO NOT use the P (continuous retry) option.  Then install
  80. MSPOOL: MSPOOL a b c.  This will route all output for LPTa
  81. through the spooler to the COMc port.  DO NOT use the MODE
  82. redirect command. (i.e. don't use MODE LPT#:=COMn)
  83.  
  84.      To spool to more than one printer, just run the spooler
  85. repeatedly, specifying each printer in turn.
  86.  
  87.      When spooling to more than one printer, in certain
  88. circumstances (see tech hype below) the last spooler loaded will
  89. have priority, then the second to last.
  90.  
  91.      In order for the Purge, Disable, Enable routine to work, you
  92. should load the spooler(s) last among the 'resident' routine(s)
  93. which intercept the printer I/O interrupt.
  94.  
  95.      Once the spooler is installed, it's output cannot be re-
  96. directed to another port, so programs written for this purpose
  97. (such as QSWAP) will not work.
  98.  
  99. Technical hype:
  100.  
  101.      This spooler intercepts 2 interrupts: Printer I/O (INT 17H),
  102. and Keyboard I/O (INT 16H).  At installation, it stores the old
  103. vectors for these interrupts internally and substitutes it's own
  104. addresses in the interrupt vector table.
  105.      Any call to print is checked as to whether it references the
  106. spooler's printer.  If not, it is passed on to the the old
  107. printer I/O handler. (could be another spooler, GRAPHICS.COM, the
  108. ROM routine etc.)  If it does reference the spooler's printer,
  109. the character is put in the spooler's buffer, and the buffer is
  110. checked to see if it's full.  If not, the spooler returns
  111. to the calling program.  Otherwise, the spooler prints the
  112. next character waiting in the buffer, then returns.  If the
  113. spooler has been 'disabled', it always prints the next character
  114. in the buffer, regardless of whether the buffer is full.
  115.      Whenever a program makes a keyboard I/O call (INT 16H), the
  116. spooler checks whether it has a character to print in it's
  117. buffer.  If not, it passes control to the old keyboard I/O
  118. routine (could be another spooler, the ROM routine etc.).
  119. Otherwise, it makes one attempt to print a character.  It then
  120. checks to see if the keyboard call will require the keyboard I/O
  121. routine to wait for a character to be entered from the keyboard
  122. if no character is already in the keyboard buffer.  If not, it
  123. passes control to the old keyboard I/O handler.  Otherwise, it
  124. looks at the BUFFER_HEAD and BUFFER_TAIL words in the ROM BIOS
  125. data area to determine if there is a character in the keyboard
  126. buffer.  If there is, it passes control.  Otherwise, it begins
  127. looping, repeatedly attempting to print and checking the keyboard
  128. buffer until it either runs out of characters or a character is
  129. entered at the keyboard.  It is during this looping process that
  130. the most recently installed spooler will get the highest
  131. priority.
  132.      Whenever mspool is run, it checks where the printer I/O
  133. interrupt vector is pointing to determine whether it has already
  134. been installed.  If it doesn't find a copy of itself there, it
  135. assumes it is not installed and continues with installation.  If
  136. there is a copy of itself, it checks to see whether the copy is
  137. configured to intercept calls to the same printer as was
  138. specified in it's own parameter list (parm 1). If not, it gets
  139. the segment for the next printer I/O handler up the line from the
  140. copy and repeats the same procedure until it either lands in
  141. unfamiliar territory or finds a spooler configured for it's
  142. printer.  If it finds one with the proper configuration, it
  143. presents you with the 'Purge, Disable, Enable' option.
  144. Otherwise, it continues with installation.
  145.      During installation, the spooler is patched in accordance
  146. with the parameters passed to it by DOS, to customize for
  147. parallel or serial printing, buffer size, LPT number and the
  148. addresses of the old interrupt routines gotten from the interrupt
  149. vector table.
  150.      The legal ranges for the printer number and serial port number
  151. are due to the fact that there is space for 4 ports in both the
  152. printer and RS-232 tables.
  153.  
  154. *
  155.  
  156. PAGE 60,132
  157. ; MULTI SPOOLER 2 BY RICH WINKEL.  FOR FREE DISTRIBUTION ONLY.
  158. ; CERTAIN AREAS OF CODE ARE MODIFIED BY THE INITIALIZATION ROUTINE TO
  159. ; CUSTOMIZE FOR THE PRINTER AND BUFFER SIZE WHILE MINIMIZING THE NEED
  160. ; FOR (SLOW) INDIRECT ADDRESSING.  (QUITE A HACK, EH?)
  161. ; THE MODIFIED CODE AREAS ARE MARKED ON THE RIGHT WITH '*'.
  162. ;
  163. CR      EQU     0DH             ;CARRIAGE RETURN
  164. ;
  165. BOTTOM  SEGMENT AT 0H
  166.         ORG 058H
  167. KBDIP   DW ?                    ;INT VECTOR FOR
  168. KBDCS   DW ?                    ;KEYBOARD I/O
  169. PRTIP   DW ?                    ;INT VECTOR FOR
  170. PRTCS   DW ?                    ;PRINTER I/O
  171.         ORG 41AH
  172. KBHEAD  DW ?                    ;ROM BIOS DATA; POINTERS TO HEAD AND
  173. KBTAIL  DW ?                    ;TAIL OF KEYBOARD BUFFER
  174. BOTTOM  ENDS
  175. ;
  176. MSPOOL  SEGMENT
  177.         ASSUME CS:MSPOOL
  178.         ORG 6H
  179. SEGTOP  DW ?                    ;NUMBER OF BYTES AVAIL IN SEGMENT
  180.         ORG 80H
  181. UPALEN  DB ?                    ;UNFORMATTED PARM AREA LENGTH
  182. ;
  183.         ORG 100H
  184. MAIN    PROC    NEAR
  185.         JMP     INIT            ;JUMP TO INITIALIZATION
  186. HEAD    DW      OFFSET PRTNUM   ;POINTER TO LAST CHAR STORED IN BUFFER
  187. TAIL    DW      OFFSET PRTNUM   ;POINTER TO LAST CHAR PRINTED
  188. ;
  189. ;       ROUTINE TO COMPUTE POINTER TO NEXT POSITION IN BUFFER
  190. INCR:   INC     BX              ;INCREMENT POINTER
  191.         CMP     BX,1234H        ;ARE WE AT END OF BUFFER?             *
  192. TOP     LABEL   WORD            ;LABEL IS 2 BYTES AFTER CODE TO MODIFY
  193.         JZ      L2              ;YES, WRAP AROUND
  194.         RET                     ;OTHERWISE, GET BACK TO CALLER
  195. L2:     MOV     BX,OFFSET PRTNUM;START OF BUFFER
  196.         RET                     ;GET BACK
  197. ;
  198. ;       PRINTER I/O INTERRUPT HANDLER
  199. PRTINT: STI                     ;INTERRUPTS BACK ON
  200.         CMP     DX,12H          ;DOES THE CALL REFERENCE OUR PRINTER? *
  201. LPTN    LABEL   BYTE            ;LABEL IS 1 BYTE AFTER CODE TO MODIFY
  202.         JZ      L3              ;YES, HANDLE IT
  203.                                 ;OTHERWISE, JUMP TO NEXT INT HANDLER
  204.         DB      0EAH            ;PREFIX BYTE FOR FAR JUMP
  205. PJFARIP DW      0H              ;IP FOR " "                           *
  206. PJFARCS DW      0H              ;CS FOR " "                           *
  207. L3:     OR      AH,AH           ;PRINT A CHARACTER?
  208.         JNZ     BACK            ;NO, REPLY PRINTER READY AND RETURN
  209.         PUSH    BX              ;OTHERWISE RECEIVE CHARACTER
  210.         MOV     BX,CS:HEAD      ;GET POINTER
  211.         CALL    INCR            ;INCR TO POINT TO NEXT BUFFER POSITION
  212.         MOV     CS:[BX],AL      ;STORE CHAR IN BUFFER
  213.         MOV     CS:HEAD,BX      ;STORE NEW HEAD VALUE
  214.         MOV     AX,BX           ;FOR SAFE KEEPING
  215.         MOV     BX,CS:TAIL      ;GET TAIL
  216.         CMP     AX,BX           ;IS THE BUFFER FULL?
  217. TOGGLE  LABEL   BYTE            ;AT BYTE TO MODIFY (SPOOLING DISABLE)
  218.         JZ      FULL            ;YES, SO PRINT A CHARACTER            *
  219.         POP     BX              ;OTHERWISE, RETURN
  220. BACK:   MOV     AH,90H          ;PRINTER STATUS READY, SELECTED
  221.         IRET                    ;GET BACK TO CALLER
  222. FULL:   PUSH    DX              ;PRINT A CHARACTER
  223.         MOV     DX,1234H        ;POINTER TO STATUS PORT OF PRINTER    *
  224. PRTADD1 LABEL   WORD            ;LABEL IS 2 BYTES AFTER CODE TO MODIFY
  225. L5:     CALL    PRT             ;CALL TO PRINT
  226.         CMP     BX,CS:TAIL      ;HAS A PRINT OCCURRED?
  227.         JZ      L5              ;NO, TRY AGAIN
  228.         MOV     CS:TAIL,BX      ;OTHERWISE, STORE NEW TAIL AND RETURN
  229.         POP     DX
  230.         POP     BX
  231.         MOV     AH,90H          ;PRINTER READY, SELECTED
  232.         IRET                    ;BYE
  233. ;
  234. ;       KEYBOARD INT HANDLER
  235. KBDINT: STI                     ;INTERRUPTS BACK ON
  236.         PUSH    BX
  237.         MOV     BX,CS:TAIL      ;GET POINTER TO LAST CHAR PRINTED
  238.         CMP     BX,CS:HEAD      ;WAS IT THE LAST CHAR SPOOLED?
  239.         JZ      L10             ;YES, JUMP TO NEXT INT HANDLER
  240.         PUSH    DX              ;OTHERWISE, PRINT A CHARACTER
  241.         PUSH    AX
  242.         MOV     DX,1234H        ;POINTER TO PRINTER STATUS PORT       *
  243. PRTADD2 LABEL   WORD            ;LABEL IS 2 BYTES AFTER CODE TO MODIFY
  244.         CALL    PRT             ;CALL TO PRINT
  245.         POP     AX
  246.         OR      AH,AH           ;TEST NATURE OF KBD CALL
  247.         JNZ     L9              ;JUMP IF WE ARE NOT TO WAIT FOR KBD INP
  248.         PUSH    AX              ;OTHERWISE, CHECK IF CHAR IN KBD BUFFER
  249.         PUSH    DS
  250.         XOR     AX,AX           ;POINT DS TO LOW MEMORY
  251.         MOV     DS,AX
  252.         ASSUME DS:BOTTOM
  253. L7:     MOV     AX,KBHEAD       ;IS THERE A CHAR
  254.         CMP     AX,KBTAIL       ;IN THE KEYBOARD BUFFER?
  255.         JNZ     L8              ;YES, JUMP TO NEXT KBD INT HANDLER
  256.         CMP     BX,CS:HEAD      ;STILL CHARS TO PRINT?
  257.         JZ      L8              ;NO, ON TO NEXT KBD INT HANDLER
  258.         CALL    PRT             ;OTHERWISE, PRINT ANOTHER CHAR
  259.         JMP     SHORT L7        ;DO IT AGAIN
  260. L8:     POP     DS
  261.         POP     AX
  262. L9:     POP     DX
  263.         MOV     CS:TAIL,BX      ;STASH LATEST VALUE OF TAIL
  264. L10:    POP     BX
  265.         DB      0EAH            ;PREFIX BYTE FOR FAR JUMP
  266. KJFARIP DW      0H              ;IP FOR " "                           *
  267. KJFARCS DW      0H              ;CS FOR " "                           *
  268. ;
  269. ;       ROUTINE TO PRINT A CHARACTER TO RS-232
  270. PRT:    IN      AL,DX           ;TEST LINE STATUS REG                **
  271.         TEST    AL,20H          ;READY?
  272.         JNZ     MSR             ;YES, CHECK MODEM STATUS REG
  273.         RET                     ;OTHERWISE, RETURN
  274. MSR:    INC     DX              ;POINT TO IT
  275.         IN      AL,DX           ;GET STATUS
  276.         AND     AL,30H          ;ISOLATE CTS & DSR
  277.         CMP     AL,30H          ;BOTH READY?
  278.         JNZ     REQUEST         ;NO, SIGNAL DTR AND RTS
  279.         SUB     DX,06H          ;ELSE POINT TO XMIT HOLDING REG
  280.         CALL    INCR            ;INCREMENT BUFFER POINTER
  281.         MOV     AL,CS:[BX]      ;GET CHAR
  282.         OUT     DX,AL           ;OUTPUT
  283.         ADD     DX,05H          ;POINT BACK TO LSR
  284.         RET                     ;GET BACK
  285. REQUEST:SUB     DX,02H          ;POINT TO MODEM CNTL REG
  286.         MOV     AL,03H          ;DTR, RTS
  287.         OUT     DX,AL           ;OUTPUT
  288.         INC     DX              ;POINT BACK TO LSR
  289.         RET                     ;GET BACK                            **
  290. ;
  291. ;-------END OF RESIDENT CODE-------
  292. ;
  293. ;       THE FOLLOWING BYTES ARE USED DURING INITIALIZATION
  294.         ASSUME DS:MSPOOL
  295. PRTNUM   DB     0H              ;FIRST PARM PASSED
  296. BUFFSIZE DB     0H              ;SECOND
  297. COMNUM   DB     0H              ;THIRD (OPTIONAL)
  298. ;
  299. ;-------INITIALIZATION ROUTINE-------
  300. ;
  301. ; FIRST PROCESS PARMS
  302. ;
  303. INIT:   MOV     CL,UPALEN       ;GET LENGTH OF PARM STRING
  304.         OR      CL,CL           ;IS IT ZERO?
  305.         JZ      OVRLOOP         ;JUMP OVER PARM PARSING
  306.         XOR     CH,CH           ;ZERO FOR LOOPING
  307.         MOV     BX,OFFSET UPALEN+1 ;POINT TO PARM AREA
  308.         MOV     SI,OFFSET PRTNUM-1 ;POINT TO PLACE TO STASH PARMS
  309. PROCESS:MOV     AL,[BX]         ;GET THE PARM
  310.         CMP     AL,' '          ;GET RID OF SPACES
  311.         JZ      LOOP1
  312.         INC     SI              ;POINT TO NEXT PARM STORAGE BYTE
  313.         CMP     SI,OFFSET COMNUM;PROTECT AGAINST USER ABUSE
  314.         JA      NOGOOD          ;EXCESSIVE NUMBER OF PARMS GIVEN
  315.         MOV     [SI],AL         ;FOR SAFE KEEPING
  316.         INC     BX              ;POINT TO NEXT SPOT IN UPA
  317.         CMP     BYTE PTR [BX],' ';WAS THE PARM A SINGLE CHAR?
  318.         JZ      LOOP2           ;GOOD
  319.         CMP     BYTE PTR [BX],13;CARRIAGE RETURN?
  320.         JZ      LOOP2           ;MUST BE AT END OF UPA
  321. NOGOOD: JMP     L25             ;ELSE INVALID PARM
  322. LOOP1:  INC     BX              ;POINT TO NEXT CHAR IN UPA
  323. LOOP2:  LOOP    PROCESS         ;BACK FOR MORE
  324. ;
  325. ; PROCESS FIRST PARM
  326. ;
  327. OVRLOOP:MOV     AL,PRTNUM       ;GET FIRST PARM
  328.         CMP     AL,0H           ;NO PARM PASSED?
  329.         JNZ     L14
  330.         MOV     AL,'1'          ;THEN ASSUME '1'
  331. L14:    CMP     AL,'1'          ;CHECK FOR BOTTOM OF LEGAL RANGE
  332.         JB      NOGOOD          ;BAD PARM
  333.         CMP     AL,'4'          ;TOP OF LEGAL RANGE
  334.         JA      NOGOOD          ;BAD PARM
  335.         SUB     AL,'1'          ;CONVERT TO CORRESPONDING HEX NUMBER-1
  336.         MOV     LPTN-1,AL       ;MODIFY CODE
  337. ;
  338. ; NOW CHECK IF SPOOLER FOR THIS PRINTER IS ALREADY INSTALLED
  339. ;
  340.         XOR     DX,DX
  341.         MOV     ES,DX
  342.         MOV     AX,ES:PRTCS     ;GET SEGMENT FOR PRT INT FROM TABLE
  343.         CLD                     ;FORWARD DIRECTION FOR COMPARE
  344. L19:    MOV     ES,AX           ;GET IN RIGHT SEGMENT
  345.         MOV     CX,0010H        ;COMPARE 10H BYTES
  346.         MOV     SI,OFFSET L3    ;PREPARE TO COMPARE
  347.         MOV     DI,SI
  348. L20:    CMPSB                   ;DOES IT MATCH?
  349.         JNZ     CONTINU         ;NO, NOT INSTALLED, CONTINUE INSTALLING
  350.         LOOP    L20             ;COMPARE NEXT BYTES
  351.         MOV     AL,ES:LPTN-1    ;THERE'S A SPOOLER THERE, BUT IS IT
  352.         CMP     AL,LPTN-1       ;CONFIGURED FOR OUR PRINTER?
  353. PATCHON LABEL   BYTE            ;PTR TO BYTE TO PATCH AT TOGGLE
  354.         JZ      L21             ;YES, PURGE, DISABLE OR ENABLE?
  355.                                 ;NO, CHECK NEXT PRT INT HANDLER UP THE
  356.                                 ;LINE
  357.         MOV     AX,ES:PJFARCS   ;GET CS FOR NEXT HANDLER
  358. PATCHOFF LABEL  BYTE            ;PTR TO BYTE TO PATCH AT TOGGLE
  359.         JMP     SHORT L19       ;CHECK IF IT'S ANOTHER SPOOLER
  360. L21:    MOV     AH,09H          ;ASK IF WANT TO PURGE, DISABLE OR
  361.         MOV     DX,OFFSET MSG4  ;ENABLE INSTALLED SPOOLER
  362.         INT     21H             ;DOS CALL
  363. L22:    MOV     AH,01H          ;GET A CHARACTER FROM THE KEYBOARD
  364.         INT     21H             ;DOS CALL
  365.         AND     AL,'_'          ;FORCE UPPER CASE
  366.         CMP     AL,'P'          ;CHECK FOR PURGE
  367.         JZ      PURGE           ;YES, PURGE
  368.         CMP     AL,'D'          ;CHECK FOR DISABLE
  369.         JZ      DISABLE         ;SWITCH OFF
  370.         CMP     AL,'E'          ;CHECK FOR ENABLE
  371.         JZ      ENABLE          ;SWITCH ON
  372.         INT     20H             ;OTHERWISE, BACK TO DOS
  373. PURGE:  MOV     AX,ES:HEAD      ;GET HEAD FROM OTHER SPOOLER
  374.         MOV     ES:TAIL,AX      ;PUT IT IN TAIL
  375.         INT     20H             ;BACK TO DOS
  376. DISABLE:MOV     AL,PATCHOFF     ;TURN IT OFF
  377.         MOV     ES:TOGGLE,AL
  378.         INT     20H             ;BYE
  379. ENABLE: MOV     AL,PATCHON      ;TURN IT ON
  380.         MOV     ES:TOGGLE,AL
  381.         INT     20H             ;BYE
  382. ;
  383. ; SPOOLER IS NOT YET INSTALLED, PROCEED WITH INSTALLATION
  384. ;
  385. CONTINU:XOR     AH,AH           ;FOR FUTURE USE
  386.         MOV     AL,COMNUM       ;COMM PORT SPECIFIED?
  387.         OR      AL,AL
  388.         JZ      PARINIT         ;NO, INSTALL FOR PARALLEL PRINTER
  389.         CMP     AL,'1'          ;ELSE CHECK FOR LEGAL RANGE (1-4)
  390.         JB      EMSG            ;BAD PARM
  391.         CMP     AL,'5'
  392.         JB      L18             ;GOOD PARM
  393. EMSG:   JMP     L25             ;ERROR: INVALID PARM
  394. L18:    SUB     AL,'1'          ;CONVERT TO CORRESPONDING HEX NUMBER-1
  395.         SHL     AL,01H          ;FOR WORD OFFSET INTO RS232 TABLE
  396.         MOV     BX,05H          ;TO ADJUST COM PORT ADDR POINTER
  397.         JMP     SHORT GETADDR   ;GO GET THE ADDRESS
  398. PARINIT:MOV     AL,LPTN-1       ;RETRIEVE LPT NUMBER
  399.         SHL     AL,01H          ;MULT BY 2 FOR WORD OFFSET IN PRT TABLE
  400.         ADD     AL,08H          ;TO POINT TO BASE OF PRINTER TABLE
  401.         MOV     BX,01H          ;TO ADJUST PARALLEL PORT ADDR POINTER
  402.         MOV     CX,DS           ;NOW OVERLAY SERIAL PRINT ROUTINE WITH
  403.         MOV     ES,CX           ;PARALLEL PRINT ROUTINE
  404.         MOV     SI,OFFSET PARAPTCH;POINT TO PATCH FOR PARALLEL PRINTER
  405.         MOV     DI,OFFSET PRT   ;POINT TO SERIAL PRINT ROUTINE
  406.         MOV     CX,PPLEN        ;LENGTH OF PARAPTCH
  407.                                 ;DIRECTION FLAG IS ALREADY CLEAR
  408.         REP     MOVSB           ;MAKE PATCH
  409. GETADDR:ADD     AX,400H         ;POINT TO PROPER TABLE (RS232 OR PARAL)
  410.         MOV     SI,AX           ;PREPARE TO GET ENTRY IN TABLE
  411.         MOV     ES,DX           ;GET IN RIGHT SEGMENT
  412.         MOV     AX,ES:[SI]      ;GET ENTRY FROM TABLE
  413.         OR      AX,AX           ;IS ANYTHING THERE?
  414.         JNZ     DEVOK           ;YES, CONTINUE
  415.         JMP     L26             ;ERROR: DEVICE NONEXISTENT
  416. DEVOK:  ADD     AX,BX           ;POINT TO PROPER STATUS PORT OF DEVICE
  417.         MOV     PRTADD1-2,AX    ;PATCH CODE
  418.         MOV     PRTADD2-2,AX    ;DITTO
  419. ;
  420. ; PROCESS BUFFER SIZE PARAMETER
  421. ;
  422.         MOV     AL,BUFFSIZE     ;GET BUFFER SIZE PARAMETER
  423.         CMP     AL,'1'          ;CHECK FOR BOTTOM OF LEGAL RANGE
  424.         JB      L25             ;ERROR IF BELOW
  425.         CMP     AL,'9'          ;CHECK FOR TOP OF LEGAL RANGE
  426.         JA      L25             ;ERROR IF ABOVE
  427.         SUB     AL,'0'          ;CONVERT TO CORRESPONDING HEX NUMBER
  428.         XOR     AH,AH
  429.         MOV     CX,1C00H        ;MULTIPLY BY
  430.         MUL     CX              ;7K TO GET BUFFER SIZE
  431.         ADD     AX,OFFSET PRTNUM;ADD RESIDENT CODE SIZE TO GET TOTAL
  432.         CMP     AX,SEGTOP       ;IS THERE ROOM?
  433.         JA      L27             ;NO, ERROR
  434.         MOV     TOP-2,AX        ;MODIFY CODE
  435. ;
  436. ;  NOW THE FINAL INSTALLATION
  437. ;
  438.         MOV     ES,DX           ;GET VECTORS FROM THE INT TABLE AT SEG 0
  439.         MOV     AX,ES:PRTIP     ;IP FOR INT 17H
  440.         MOV     PJFARIP,AX      ;MODIFY CODE
  441.         MOV     AX,ES:PRTCS     ;CS FOR INT 17H
  442.         MOV     PJFARCS,AX      ;MODIFY CODE
  443.         MOV     AX,ES:KBDIP     ;IP FOR INT 16H
  444.         MOV     KJFARIP,AX      ;MODIFY CODE
  445.         MOV     AX,ES:KBDCS     ;CS FOR INT 16H
  446.         MOV     KJFARCS,AX      ;MODIFY CODE
  447.         MOV     AX,2517H        ;USE DOS TO POINT INT 17H TO US
  448.         MOV     DX,OFFSET PRTINT;ADDR OF PRINT INT HANDLER
  449.         INT     21H             ;ADJUST INTERRUPT
  450.         MOV     AX,2516H        ;USE DOS TO POINT INT 16H TO US
  451.         MOV     DX,OFFSET KBDINT;ADDR OF KBD INT HANDLER
  452.         INT     21H             ;DO IT
  453.         MOV     AH,09H          ;MESSAGE TO USER:
  454.         MOV     DX,OFFSET MSG5  ;'SPOOLER INSTALLED'
  455.         INT     21H             ;DO IT
  456.         MOV     DX,TOP-2        ;GET TOTAL SIZE OF SPOOLER
  457.         INT     27H             ;TERMINATE AND STAY RESIDENT
  458. ;
  459. ;    ERROR MESSAGES
  460. ;
  461. L25:    MOV     AH,09H          ;MESSAGE: 'BAD PARMS'
  462.         MOV     DX,OFFSET MSG1
  463.         INT     21H
  464.         INT     20H             ;ADIOS
  465. L26:    MOV     AH,09H          ;MESSAGE: 'NO PORT!
  466.         MOV     DX,OFFSET MSG2
  467.         INT     21H
  468.         INT     20H             ;ADIOS
  469. L27:    MOV     AH,09H          ;MESSAGE: 'NOT ENUF ROOM!'
  470.         MOV     DX,OFFSET MSG3
  471.         INT     21H
  472.         INT     20H             ;ADIOS
  473. ;
  474. MSG1    DB 'Error: Invalid parameter(s).',0DH,0AH
  475.         DB 'Parm 1 represents the printer and must be >0 and <5.',0DH,0AH
  476.         DB 'Parm 2 is the size of the buffer in 7K blocks and must be '
  477.         DB '>0 and <10.',0DH,0AH
  478.         DB 'Parm 3 is the optional COM port to re-direct to, and must '
  479.         DB 'be >0 and <5.$'
  480. MSG2    DB 'Error: Output port non-existent!$'
  481. MSG3    DB 'Error: Not enough memory for requested buffer.$'
  482. MSG4    DB 'Mspool2 already installed.  Purge, Disable, Enable? (P/D/E): $'
  483. MSG5    DB  0DH,0AH,09H,'Multi Spooler2 by Rich Winkel',0DH,0AH,0AH
  484.         DB  09H,'>> Multi Spooler installed <<',0DH,0AH,'$'
  485. ;
  486. ;
  487. ;PATCH TO PRINT TO PARALLEL PRINTER (OVERLAYS PRT)
  488. ;
  489. PARAPTCH LABEL BYTE
  490.         IN      AL,DX           ;GET PRINTER STATUS
  491.         TEST    AL,80H          ;READY?
  492.         JZ      L99             ;NO, GET BACK
  493. ; THE FOLLOWING 3 BYTES ARE A CALL TO THE INCR ROUTINE.
  494. ; HOWEVER, THE OFFSET WORD FOR THE CALL HAD TO BE ADJUSTED
  495. ; FOR THE ACTUAL LOCATION OF THIS ROUTINE WHEN IT IS
  496. ; USED, SINCE IT WOULD BE PATCHED OVER THE ROUTINE 'PRT'.
  497.         DB      0E8H            ;PREFIX BYTE FOR INTRASEGMENT CALL
  498.         DW      SETOFF + OFFSET PARAPTCH - JNK
  499. JNK     EQU     $
  500.         MOV     AL,CS:[BX]      ;GET CHAR
  501.         DEC     DX              ;POINT TO CHAR OUT PORT
  502.         OUT     DX,AL           ;GET IT GONE
  503.         INC     DX              ;POINT TO
  504.         INC     DX              ;STROBE PORT
  505.         MOV     AL,1DH          ;ZAP IT
  506.         OUT     DX,AL
  507.         MOV     AL,1CH          ;STROBE OFF
  508.         OUT     DX,AL
  509.         DEC     DX              ;POINT BACK TO STATUS PORT
  510. L99:    RET                     ;GET BACK
  511. PPLEN   EQU     $-OFFSET PARAPTCH       ;LENGTH OF PATCH ABOVE
  512. SETOFF  EQU     OFFSET INCR - OFFSET PRT ;TO USE TO ADJUST CALL IN
  513.                                          ;PATCH FOR PARA PRINTER
  514. MAIN    ENDP
  515. MSPOOL  ENDS
  516.         END     MAIN
  517.